package com.wingice.system.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wingice.common.page.EntityPageBean;
import com.wingice.exception.BusinessException;
import com.wingice.spring.security.common.utils.SecurityUtils;
import com.wingice.spring.security.model.KnifeUser;
import com.wingice.system.constant.SecurityConstant;
import com.wingice.system.entity.*;
import com.wingice.system.exception.SysBusinessCode;
import com.wingice.system.exception.SysBusinessException;
import com.wingice.system.mapper.SysUserMapper;
import com.wingice.system.service.*;
import com.wingice.system.vo.SysUserView;
import com.wingice.utils.transfer.TransferUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author 胡昊
 * @since 2020-07-23
 */
@Transactional
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private SysRoleUserService sysRoleUserService;
    @Resource
    private SysRoleResourceService sysRoleResourceService;
    @Resource
    private SysResourceService sysResourceService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public KnifeUser loadUserByUsername(String username) throws UsernameNotFoundException {
        final SysUser sysUser = getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));
        if (sysUser == null) {
            return null;
        }
        final KnifeUser knifeUser = new KnifeUser();
        BeanUtils.copyProperties(sysUser, knifeUser);
        final List<SysRoleUser> sysRoleUserList = sysRoleUserService.list(Wrappers.<SysRoleUser>lambdaQuery().eq(SysRoleUser::getUserId, sysUser.getId()));
        if (!CollectionUtils.isEmpty(sysRoleUserList)) {
            final List<SysRole> sysRoleList = sysRoleService.listByIds(sysRoleUserList.stream().map(SysRoleUser::getRoleId).collect(Collectors.toSet()));
            knifeUser.setRoleKeyList(sysRoleList.stream().map(SysRole::getRoleKey).collect(Collectors.toList()));
            final List<SysRoleResource> sysRoleResourceList = sysRoleResourceService.list(Wrappers.<SysRoleResource>lambdaQuery().in(SysRoleResource::getRoleId, sysRoleUserList.stream().map(SysRoleUser::getRoleId).collect(Collectors.toList())));
            if (!CollectionUtils.isEmpty(sysRoleResourceList)) {
                final List<SysResource> sysResourceList = sysResourceService.listByIds(sysRoleResourceList.stream().map(SysRoleResource::getResourceId).collect(Collectors.toList()));
                if (!CollectionUtils.isEmpty(sysResourceList)) {
                    knifeUser.setPermissionList(sysResourceList.stream().map(SysResource::getPermission).filter(StringUtils::hasText).collect(Collectors.toList()));
                    knifeUser.setSysResourceList(sysResourceList);
                }
            }
        }
        return knifeUser;
    }

    @Override
    public Boolean insert(SysUser sysUser) {
        if (count(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, sysUser.getUsername())) > 0) {
            throw new SysBusinessException(SysBusinessCode.USERNAME_EXIST_ERROR);
        }
        //填充用户来源
        sysUser.setUserSource(SecurityConstant.USER_SOURCE);
        //密码加密
        sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
        return save(sysUser);
    }

    @Override
    public Boolean deleteBatch(List<String> idList) {
        //删除用户角色关联
        sysRoleUserService.remove(Wrappers.<SysRoleUser>lambdaQuery().in(SysRoleUser::getUserId, idList));
        return removeByIds(idList);
    }

    @Override
    public Boolean update(SysUser sysUser) {
        if (count(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUsername, sysUser.getUsername())
                .ne(SysUser::getId, sysUser.getId())) > 0) {
            throw new SysBusinessException(SysBusinessCode.USERNAME_EXIST_ERROR);
        }
        if (StringUtils.hasText(sysUser.getPassword())) {
            final SysUser sysUserOld = getById(sysUser.getId());
            //如果密码与原先不一致则代表密码更新
            if (!sysUser.getPassword().equals(sysUserOld.getPassword()) && !passwordEncoder.matches(sysUser.getPassword(), sysUserOld.getPassword())) {
                sysUser.setPassword(passwordEncoder.encode(sysUser.getPassword()));
            } else {
                sysUser.setPassword(null);
            }
        }
        return updateById(sysUser);
    }

    @Override
    public Boolean userUpdatePassword(String oldPassword, String newPassword) {
        final KnifeUser knifeUser = SecurityUtils.getUser();
        final SysUser oldUser = getById(knifeUser.getId());
        if (!passwordEncoder.matches(oldPassword, oldUser.getPassword())) {
            throw new BusinessException("旧密码错误");
        }
        final SysUser sysUser = new SysUser();
        sysUser.setId(knifeUser.getId());
        sysUser.setPassword(passwordEncoder.encode(newPassword));
        return updateById(sysUser);
    }

    @Override
    public Page<SysUserView> pageUser(EntityPageBean<SysUser> entityPageBean) {
        final Page<SysUser> page = page(TransferUtils.pageEntityToPage(entityPageBean), Wrappers.<SysUser>lambdaQuery()
                .like(StringUtils.hasText(entityPageBean.getEntity().getUsername()), SysUser::getUsername, entityPageBean.getEntity().getUsername())
                .like(StringUtils.hasText(entityPageBean.getEntity().getName()), SysUser::getName, entityPageBean.getEntity().getName())
                .like(StringUtils.hasText(entityPageBean.getEntity().getMail()), SysUser::getMail, entityPageBean.getEntity().getMail())
                .like(StringUtils.hasText(entityPageBean.getEntity().getPhone()), SysUser::getPhone, entityPageBean.getEntity().getPhone())
                .eq(entityPageBean.getEntity().getGender() != null, SysUser::getGender, entityPageBean.getEntity().getGender())
                .eq(entityPageBean.getEntity().getIsAccountNonExpired() != null, SysUser::getIsAccountNonExpired, entityPageBean.getEntity().getIsAccountNonExpired())
                .eq(entityPageBean.getEntity().getIsAccountNonLocked() != null, SysUser::getIsAccountNonLocked, entityPageBean.getEntity().getIsAccountNonLocked())
                .eq(entityPageBean.getEntity().getIsCredentialsNonExpired() != null, SysUser::getIsCredentialsNonExpired, entityPageBean.getEntity().getIsCredentialsNonExpired())
                .eq(entityPageBean.getEntity().getIsEnabled() != null, SysUser::getIsEnabled, entityPageBean.getEntity().getIsEnabled()));
        if (CollectionUtils.isEmpty(page.getRecords())) {
            return new Page<>();
        }
        final List<SysRoleUser> allSysRoleUserList = sysRoleUserService.list(Wrappers.<SysRoleUser>lambdaQuery()
                .in(SysRoleUser::getUserId, page.getRecords()
                        .stream()
                        .map(SysUser::getId)
                        .collect(Collectors.toList())));
        final List<SysRole> allSysRoleList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(allSysRoleUserList)) {
            allSysRoleList.addAll(sysRoleService.listByIds(allSysRoleUserList.stream().map(SysRoleUser::getRoleId).collect(Collectors.toList())));
        }
        final List<SysUserView> sysUserViewList = page.getRecords().stream().map(sysUser -> {
            final SysUserView sysUserView = new SysUserView();
            BeanUtils.copyProperties(sysUser, sysUserView);
            final List<String> roleIdList = allSysRoleUserList.stream()
                    .filter(sysRoleUser -> sysRoleUser.getUserId().equals(sysUser.getId()))
                    .map(SysRoleUser::getRoleId)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(roleIdList)) {
                sysUserView.setSysRoleList(allSysRoleList.stream()
                        .filter(sysRole -> roleIdList.contains(sysRole.getId()))
                        .collect(Collectors.toList()));
            }
            return sysUserView;
        }).collect(Collectors.toList());
        return TransferUtils.transferPageInfo(page, sysUserViewList);
    }
}
